<?php
/**
 * class.image.php          图片操作类
 *
 * @author                  mashanling(msl-138@163.com)
 * @date                    2012-02-25 16:29:24
 * @last modify             2012-09-27 17:15:05 by mashanling
 */

!defined('ROOT') && exit('Access Denied');

class Image {

    /**
     * 生成图像验证码
     *
     * @param ing     $length       验证码长度，默认4
     * @param int     $mode         验证码类型，默认0，去掉了容易混淆的字符oOLl和数字01
     * @param int     $width        验证码图片宽度，默认40
     * @param int     $height       验证码图片高度，默认20
     * @param int    $offset        验证码开始偏移量，如验证码为abcd，$offset = 1, 则session = bcda; $offset = 2, 则session = cdab，依此类推...，默认为0，验证码倒序
     * @param string  $type         图片类型，默认png
     * @param string  $verify_name  验证码session名称，默认verify_code
     *
     * @return void 无回返值
     */
    static function buildVerifyImage($length = 4, $mode = 0, $width = 40, $height = 20, $offset = 1, $type = 'png', $verify_name = null) {
        $rand_string = rand_string($length, $mode);
        $width       = ($length * 9 + 10) > $width ? $length * 9 + 10 : $width;

        if ($type != 'gif' && function_exists('imagecreatetruecolor')) {
            $im = imagecreatetruecolor($width, $height);
        }
        else {
            $im = imagecreate($width, $height);
        }

        $r     = array(225, 255, 255, 223);
        $g     = array(225, 236, 237, 255);
        $b     = array(225, 236, 166, 125);
        $key   = mt_rand(0, 3);

        $back_color   = imagecolorallocate($im, $r[$key], $g[$key], $b[$key]); //背景色（随机）
        $border_color = imagecolorallocate($im, 100, 100, 100); //边框色

        imagefilledrectangle($im, 0, 0, $width - 1, $height - 1, $back_color);
        imagerectangle($im, 0, 0, $width - 1, $height - 1, $border_color);

        for ($i = 0; $i < 50; $i ++) {
            $rand_color = imagecolorallocate($im, rand(0, 255), rand(0, 255), rand(0, 255));
            imagesetpixel($im, rand() % 70, rand() % 30, $rand_color);
        }

        for ($i = 0; $i < $length; $i ++) {
            $font_color = imagecolorallocate($im, rand(100, 255), rand(0, 100), rand(100, 255));
            imagestring($im, 6, 5 + $i * 10, 3, $rand_string{$i}, $font_color);
        }

        if ($offset) {

        }

        self::setVerifySession($rand_string, $offset, $verify_name);//设置session

        self::output($im, $type);//输出图像
    }//end buildVerifyImage

    /**
     * 创建图像资源
     *
     * @param array  $info     图像信息
     * @param string $filename 文件名
     *
     * @return resource 图像资源
     */
    static function createImage($info, $filename) {
        $image_fun = str_replace('/','createfrom',$info['mime']);

        return $image_fun($filename);
    }

    /**
     * 获取图片信息
     *
     * @param string $img 图片路径
     *
     * @return mixed 如果正确读取，返回图片信息，否则返回false
     */
    static function getImageInfo($img) {
        $image_info = getimagesize($img);

        if ($image_info === false) {
            return false;
        }

        if (function_exists('image_type_to_extension')) {
            $image_type = image_type_to_extension($image_info[2], false);
        }
        else {
            $image_type = substr($img, strrpos($img, '.') + 1);
        }

        return array(
            'width' => $image_info[0],
            'height' => $image_info[1],
            'type' => strtolower($image_type),
            'size' => filesize($img),
            'mime' => $image_info['mime']
        );
    }

    /**
     * 输出图像
     *
     * @param resource $im   图像资源
     * @param string   $type 图像类型
     *
     * @return void 无返回值
     */
    static function output($im, $type = 'png') {
        header('Content-type: image/' . $type);
        $image_fun = 'image' . $type;
        $image_fun($im);
        imagedestroy($im);
    }

    /**
     * 产生随机字符串，可用来自动生成密码 默认长度6位 字母和数字混合
     *
     * @param ing    $len        长度，默认4
     * @param int    $type       模式，默认0，去掉了容易混淆的字符oOLl和数字01
     * @param string $add_chars  额外字符，默认空
     *
     * @return string 随机字符串
     */
    static function rand_string($len = 4, $mode = 0, $add_chars = '') {
        $str = '';

        switch ($mode) {
            case 1://大小写字母
                $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' . $add_chars;
                break;

            case 2://数字
                $chars = str_repeat('0123456789', 3);
                break;

            case 3://大写字母
                $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . $add_chars;
                break;

            case 4://小写字母
                $chars = 'abcdefghijklmnopqrstuvwxyz' . $add_chars;
                break;

            default://默认去掉了容易混淆的字符oOLl和数字01，要添加请使用add_chars参数
                $chars = 'ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789' . $add_chars;
                break;
        }

        if ($len > 10) { //位数过长重复字符串一定次数
            $chars = $mode == 2 ? str_repeat($chars, $len) : str_repeat($chars, 5);
        }

        $chars = str_shuffle($chars);
        $str   = substr($chars, 0, $len);

        return $str;
    }

    /**
     * 缩放图片
     *
     * @param string $src_file   源图片
     * @param int    $to_w       缩放至宽度
     * @param int    $to_h       缩放至高度
     * @param int    $to_file    缩放至图片，默认空
     * @param string $suffix     缩略图标识，默认_thumb
     * @param bool   $unlink_src 是否删除原图，默认false，不删除
     *
     * @return mixed 缩放成功，返回true，否则返回false
     */
    static function resize($src_file, $to_w, $to_h, $to_file = '', $suffix = '_thumb', $unlink_src = false) {

        if (!$to_w || !$to_h) {
            return false;
        }

        $src_info   = self::getImageInfo($src_file);

        if ($src_info === false) {
            return false;
        }

        $image_type = $src_info['type'];
        $to_file    = $to_file ? $to_file : substr($src_file, 0, strrpos($src_file, '.')) . $suffix . '.' . $image_type;
        $image      = self::createImage($src_info, $src_file);
        $src_w      = imagesx($image);
        $src_h      = imagesy($image);
        $src_wh     = $src_w / $src_h;
        $to_wh      = $to_w / $to_h;

        if ($src_wh >= $to_wh) {
            $to_h = $src_w > $to_w ? $to_w * $src_h / $src_w : $to_h;
        }
        else {
            $to_w = $src_h > $to_h ? $to_h * $src_w / $src_h : $to_w;
        }

        $image_p    = imagecreatetruecolor($to_w, $to_h);
        $image_func = 'image' . $image_type;
        imagecopyresampled($image_p, $image, 0, 0, 0, 0, $to_w, $to_h, $src_w, $src_h);
        $image_type == 'jpeg' ? imagejpeg($image_p, $to_file, 100) : $image_func($image_p, $to_file);
        imagedestroy($image_p);
        $unlink_src && unlink($src_file);

        return $to_file;
    }//end resize

    /**
     * 设置验证码session
     *
     * @param string $string
     * @param int    $offset 验证码开始偏移量，如验证码为abcd，$offset = 1, 则session = bcda; $offset = 2, 则session = cdab，依此类推...，默认为0，验证码倒序
     * @param string $verify_name  验证码session名称，默认verify_code
     *
     * @return void 无返回值
     */
    static function setVerifySession($string, $offset = 0, $verify_name = null) {
        return session($verify_name ? $verify_name : SESSION_VERIFY_CODE, $string);

        $verify_name = $verify_name ? $verify_name : SESSION_VERIFY_CODE;
        $string      = strtolower($string);
        $len         = strlen($string);

        if ($string && $offset < $len) {
            $string = substr($string, $offset) . substr($string, 0, $offset);
        }
        else {
            $string = strrev($string);
        }

        session($verify_name, $string);
    }

    /**
     * 显示服务器图像文件，如果图片不存在，则创建图像文件
     *
     * @param string $img_file 图片路径，
     * @param string $text
     * @param int    $width
     * @param int    $height
     *
     * @return bool true
     */
    static function showImg($img_file, $text = '', $width = 80, $height = 30) {
        $info = self::getImageInfo($img_file); //获取图像文件信息

        if ($info !== false) {
            $im = self::createImage($info, $img_file);

            if ($im) {
                $image_fun = str_replace('/', '', $info['mime']);

                if (! empty($text)) {
                    $tc = imagecolorallocate($im, 0, 0, 0);
                    imagestring($im, 3, 5, 5, $text, $tc);
                }

                if ($info['type'] == 'png' || $info['type'] == 'gif') {
                    imagealphablending($im, false); //取消默认的混色模式
                    imagesavealpha($im, true);      //设定保存完整的 alpha 通道信息
                }

                header('content-type: ' . $info['mime']);
                $image_fun($im);
                imagedestroy($im);

                return true;
            }
        }

        $im  = imagecreatetruecolor($width, $height);//获取或者创建图像文件失败则生成空白PNG图片
        $bgc = imagecolorallocate($im, 255, 255, 255);
        $tc  = imagecolorallocate($im, 0, 0, 0);

        imagefilledrectangle($im, 0, 0, 150, 30, $bgc);
        imagestring($im, 4, 5, 5, 'NO PIC', $tc);
        self::output($im);

        return true;
    }//end showImg

    /**
     * 添加水印
     *
     * @param string $image      待加水印图片
     * @param string $background 背景图或水印文字
     * @param string $position   水印位置
     *
     * @return bool 成功添加，返回true，否则返回错误信息
     */
    static function water($image, $background, $to_file = '', $position = 'br', $unlink_src = false, $trans = 20, $offset_x = 0, $offset_y = 0) {

        if (!file_exists($image)) {
            return '待加水印图片不存在';
        }

        $image_info = self::getImageInfo($image);    //图片大小
        $image_w    = $image_info['width'];     //图片宽
        $image_h    = $image_info['height'];    //图片高
        $image_type = $image_info['type'];
        $src_image  = self::createImage($image_info, $image);

        if (file_exists($background)) {    //水印为图片
            $water_info  = self::getImageInfo($background);
            $width       = $water_w = $water_info['width'];    //水印宽
            $height      = $water_h = $water_info['height'];    //水印高
            $water_image = self::createImage($water_info, $background);
        }
        else {    //水印字体

            if (!file_exists($this->font)) {
                return '水印字体不存在';
            }

            $font_info = imagettfbbox($this->font_size, 0, $this->font, $background);
            $width  = $font_info[2] - $font_info[6];
            $height = $font_info[3] - $font_info[7];
            unset($font_info);
        }

        if ($image_w < $width || $image_h < $height) {
            return '图片水印图片或文字区域还小，无法生成水印';
        }

        $position_w   = $image_w - $width;
        $position_h   = $image_h - $height;
        $position_x_c = $position_w / 2;
        $position_y_c = $position_h / 2;

        switch ($position) {
            case 'tl':    //顶部居左
                $position_x = 0;
                $position_y = 0;
                break;

            case 'tc':    //顶部居中
                $position_x = $position_x_c;
                $position_y = 0;
                break;

            case 'tr':    //顶部居右
                $position_x = $position_w;
                $position_y = 0;
                break;

            case 'cl':    //中部居左
                $position_x = 0;
                $position_y = $position_y_c;
                break;

            case 'cc':    //中部居中
                $position_x = $position_x_c;
                $position_y = $position_y_c;
                break;

            case 'cr':    //中部居右
                $position_x = $position_w;
                $position_y = $position_y_c;
                break;

            case 'bl':    //底部居左
                $position_x = 0;
                $position_y = $position_h;
                break;

            case 'bc':    //底部居中
                $position_x = $position_x_c;
                $position_y = $position_h;
                break;

            case 'br':    //底部居右
                $position_x = $position_w;
                $position_y = $position_h;
                break;

            default:
                $position_x = rand(0, $position_w);
                $position_y = rand(0, $position_h);
                break;
        }

        $position_x += $offset_x;
        $position_y += $offset_y;

        imagealphablending($src_image, true);

        if (isset($water_image)) {    //水印图片
            imagecopymerge($src_image, $water_image, $position_x, $position_y, 0, 0, $water_w, $water_h, $trans);
        }
        else {

            if (strlen($this->color) == 7) {
                $red   = hexdec(substr($this->color, 1, 2));
                $green = hexdec(substr($this->color, 3, 2));
                $blue  = hexdec(substr($this->color, 5));
            }
            else {
                $red   = rand(0, 255);
                $green = rand(0, 255);
                $blue  = rand(0, 255);
            }

            imagettftext($src_image, $this->font_size, 0, $position_x, $position_y + $height, imagecolorallocatealpha($src_image, $red, $green, $blue, 80), $this->font, $background);
        }

        $unlink_src && unlink($image);

        $to_file = $to_file ? $to_file : $image;

        switch ($image_info['mime']) {
            case 'image/gif':
                imagegif($src_image, $to_file);
                break;

            case 'image/jpeg':
                imagejpeg($src_image, $to_file, 100);
                break;

            default:
                imagepng($src_image, $to_file);
                break;
        }

        if (isset($water_image)) {
            unset($water_image);
        }

        if (isset($water_image)) {
            imagedestroy($water_image);
        }

        unset($image_info);

        imagedestroy($src_image);

        return true;
    }//end water
}